home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / TSR / PPTSR10 / TSR.PAS < prev    next >
Pascal/Delphi Source File  |  1993-02-12  |  21KB  |  838 lines

  1. (*
  2.  * Functions for TSR programming.
  3.  * Inspired by article published in german magazine "DOS International"
  4.  * june 1992 by Reiner Wahler
  5.  *
  6.  * any questions, bugs, additions, remarks,...
  7.  * can be sent by e-mail to "pp@win.tue.nl"
  8.  *
  9.  * To create the object module tsr.obj from tsr.asm, extract trs3.asm
  10.  * from this source and assemble it using : "tasm tsr.asm"
  11.  * To activate the debugging info in the assembly part assemble
  12.  * tsr.asm using : "tasm /ddebug tsr.asm"
  13.  * To activate the debugging info in the pascal part change the
  14.  * "undef debug" below into "define debug"
  15.  *)
  16.  
  17. {$undef debug}
  18.  
  19. (*
  20. ;;Program  : tsr.asm
  21. ;;Function : Routines for TSR programs
  22. ;;Language : Tasm 2.0
  23. ;;From     : DOS International, June 1992
  24. ;;Modified : by P.Peters June 1992 (pp@win.tue.nl)
  25. ;;           modified so it worked....
  26. ;;           added check of indos and idle flag and
  27. ;;           debugging code.
  28. ;;           changed some names to be more meaningfull.
  29. ;
  30. ;data    segment   word public
  31. ;
  32. ;        extrn     TurboSS      : word   ;stack segment
  33. ;        extrn     TurboSP      : word   ;stack pointer
  34. ;        extrn     DosVars      : dword  ;os variable area
  35. ;        extrn     OldInts      : dword  ;old vectors
  36. ;        extrn     NewInts      : dword  ;Catch routines
  37. ;        extrn     PrefixSeg    : word   ;prefix segment
  38. ;        extrn     Int2fId      : byte   ;program id
  39. ;        extrn     User2FServer : dword  ;User 2F interface
  40. ;        extrn     ExeName      : byte   ;for test if already installed
  41. ;
  42. ;data    ends
  43. ;
  44. ;code    segment   byte public
  45. ;
  46. ;        extrn     TurboFrame   : near
  47. ;        public    SetUp
  48. ;        public    Dummy1B
  49. ;
  50. ;        assume    cs:code,ds:data
  51. ;
  52. ;;
  53. ;; offsets of new vectors. take care to use the same order as in
  54. ;; pascal counterpart
  55. ;;
  56. ;SerVer   dw        offset Server08
  57. ;         dw        offset Server09
  58. ;         dw        offset Catch10
  59. ;         dw        offset Catch13
  60. ;         dw        offset Catch16
  61. ;         dw        offset Catch25
  62. ;         dw        offset Catch26
  63. ;         dw        offset Server28
  64. ;         dw        offset Catch2a
  65. ;         dw        offset Server2f
  66. ;
  67. ;;
  68. ;; addresses of original vectors
  69. ;; must be in the same order as in the pascal counterpart as well
  70. ;;
  71. ;Int08    dd        ?
  72. ;Int09    dd        ?
  73. ;Int10    dd        ?
  74. ;Int13    dd        ?
  75. ;Int16    dd        ?
  76. ;Int25    dd        ?
  77. ;Int26    dd        ?
  78. ;Int28    dd        ?
  79. ;Int2a    dd        ?
  80. ;Int2f    dd        ?
  81. ;
  82. ;;
  83. ;; stack of interrupted program
  84. ;;
  85. ;SSsave   dw        ?
  86. ;SPSave   dw        ?
  87. ;
  88. ;;
  89. ;;address of Indos flag
  90. ;;
  91. ;InDosAdr dd        ?
  92. ;
  93. ;IFDEF debug
  94. ;;
  95. ;;Here is an extra routine to do updates on flags normally
  96. ;;not displayed.
  97. ;;
  98. ;Show     proc near
  99. ;         push ax
  100. ;         push es
  101. ;         push di
  102. ;         les  di,[DosVars]
  103. ;         mov  ax,es:[di]
  104. ;         mov  cs:[exterr],ax
  105. ;         les  di,[InDosAdr]
  106. ;         mov  ah,es:[di]
  107. ;         mov  cs:[indos],ah
  108. ;         pop  di
  109. ;         pop  es
  110. ;         pop  ax
  111. ;         ret
  112. ;Show     endp
  113. ;;
  114. ;;add an easy to find marker to check the tsr flags
  115. ;;I use "xraymon" (a tsr memory monitor) to do that....
  116. ;;
  117. ;         db        'flag: indos(1) extended error(2) request(1)'
  118. ;         db        ' active(1) bioscrit(1) doscrit(1) idle(1)'
  119. ;indos    db        0
  120. ;exterr   dw        0
  121. ;
  122. ;ENDIF
  123. ;
  124. ;;
  125. ;; flags
  126. ;;
  127. ;request  db        0                     ;activation requested ?
  128. ;active   db        0                     ;already active ?
  129. ;bioscrit db        0                     ;bios critical ints active ?
  130. ;doscrit  db        0                     ;set by int2a (dos critical region)
  131. ;idle     db        0                     ;set by int28
  132. ;
  133. ;;
  134. ;;copies of datasegment variables
  135. ;;
  136. ;id       db        ?                     ;id for int 2fh
  137. ;hotkey   dw        ?                     ;activation keyboard code
  138. ;
  139. ;Activate proc near
  140. ;;
  141. ;;activation routine
  142. ;;started by Server08 or by DOS via Server28
  143. ;;
  144. ;         pushf
  145. ;         cmp  word ptr [request],1       ;is it requested and not active
  146. ;         jne  noact                      ;nope
  147. ;         cmp  word ptr [bioscrit],0      ;check bioscrit and doscrit
  148. ;                                         ;in one check
  149. ;         jne  noact                      ;not safe !
  150. ;         mov  [active],1                 ;indicate activity
  151. ;         push ax                         ;save registers
  152. ;         push ds
  153. ;         mov  ax,data                    ;set data segment
  154. ;         mov  ds,ax
  155. ;         mov  SSSave,ss                  ;save stack ptr and seg
  156. ;         mov  SPSave,sp
  157. ;         mov  ss,TurboSS                 ;set turbo stack
  158. ;         mov  sp,TurboSP
  159. ;         push bx                         ;save registers
  160. ;         push cx
  161. ;         push dx
  162. ;         push di
  163. ;         push si
  164. ;         push es
  165. ;         cmp  [idle],1
  166. ;         je   idleact
  167. ;         les  di,[InDosAdr]
  168. ;         mov  ah,es:[di]
  169. ;         cmp  ah,0
  170. ;         jne  crit
  171. ;         les  di,[DosVars]
  172. ;         mov  ax,es:[di]
  173. ;         cmp  ax,0
  174. ;         jne  crit
  175. ;idleact:
  176. ;         sti                             ;enable int's
  177. ;         call TurboFrame
  178. ;         cli                             ;don't disturb
  179. ;         mov  [request],0
  180. ;crit:
  181. ;         pop  es                         ;restore registers
  182. ;         pop  si
  183. ;         pop  di
  184. ;         pop  dx
  185. ;         pop  cx
  186. ;         pop  bx
  187. ;         mov  ss,SSSave
  188. ;         mov  sp,SPSave
  189. ;         pop  ds
  190. ;         pop  ax
  191. ;         mov  [active],0
  192. ;noact:
  193. ;         popf
  194. ;         ret
  195. ;Activate endp
  196. ;
  197. ;Server08 proc far
  198. ;;
  199. ;;Int 08h clock tick
  200. ;;
  201. ;         pushf
  202. ;         call [Int08]
  203. ;IFDEF debug
  204. ;         call Show                       ;copy indos and
  205. ;                                         ; extended error flags
  206. ;ENDIF
  207. ;         call Activate
  208. ;         iret
  209. ;Server08 endp
  210. ;
  211. ;Server09 proc far
  212. ;;
  213. ;;Int 09h keyboard
  214. ;;check for hotkey and setup for activation if hotkey detected
  215. ;;
  216. ;         pushf
  217. ;         call [Int09]
  218. ;         push ax
  219. ;         push bx
  220. ;         push es
  221. ;         mov  ax,40h                    ;bios data seg
  222. ;         mov  es,ax
  223. ;         mov  bx,es:[1ch]               ;kbd buffer
  224. ;         dec  bx
  225. ;         dec  bx
  226. ;         cmp  bx,1eh                    ;check if at end
  227. ;         jge  NoLow
  228. ;         mov  bx,3ch
  229. ;Nolow:
  230. ;         mov  ax,es:[bx]
  231. ;         cmp  ax,[HotKey]               ;is this our hotkey ?
  232. ;         jne  NoKey                     ;no, all trouble was no use
  233. ;         mov  es:[1ch],bx
  234. ;         cmp  [active],0                ;tsr already active ?
  235. ;         jne  NoKey                     ;yes, do not request again!
  236. ;         mov  [request],1               ;request activation
  237. ;NoKey:
  238. ;         pop   es
  239. ;         pop   bx
  240. ;         pop   ax
  241. ;         iret
  242. ;Server09 endp
  243. ;
  244. ;;
  245. ;;Catch routines for critical bios interrupts
  246. ;;
  247. ;
  248. ;Catch10  proc far
  249. ;;
  250. ;;Int 10h Video
  251. ;;
  252. ;         pushf
  253. ;         inc  [bioscrit]
  254. ;         call [Int10]
  255. ;         pushf
  256. ;         dec  [bioscrit]
  257. ;         popf
  258. ;         iret
  259. ;Catch10  endp
  260. ;
  261. ;Catch13  proc far
  262. ;;
  263. ;;Int 13h Harddisk
  264. ;;
  265. ;         pushf
  266. ;         inc  [bioscrit]
  267. ;         call [Int13]
  268. ;         pushf
  269. ;         dec  [bioscrit]
  270. ;         popf
  271. ;         retf 2
  272. ;Catch13  endp
  273. ;
  274. ;Catch16  proc far
  275. ;;
  276. ;;Int 16h Keyboard
  277. ;;
  278. ;         pushf
  279. ;         inc  [bioscrit]
  280. ;         call [Int16]
  281. ;         push ax
  282. ;         pushf
  283. ;         pop  ax
  284. ;         push bp
  285. ;         mov  bp,sp
  286. ;         mov  [bp+8],ax
  287. ;         pop  bp
  288. ;         pop  ax
  289. ;         pushf
  290. ;         dec  [bioscrit]
  291. ;         popf
  292. ;         iret
  293. ;Catch16  endp
  294. ;
  295. ;Catch25  proc far
  296. ;;
  297. ;;Int 25h Abs disk read
  298. ;;
  299. ;         inc  [bioscrit]
  300. ;         call [Int25]
  301. ;         pushf
  302. ;         dec  [bioscrit]
  303. ;         popf
  304. ;         retf
  305. ;Catch25  endp
  306. ;
  307. ;Catch26  proc far
  308. ;;
  309. ;;Int 26h Abs disk write
  310. ;;
  311. ;         inc  [bioscrit]
  312. ;         call [Int26]
  313. ;         pushf
  314. ;         dec  [bioscrit]
  315. ;         popf
  316. ;         retf
  317. ;Catch26  endp
  318. ;
  319. ;Server28 proc far
  320. ;;
  321. ;;Int 28h is used by dos when keyboard input is
  322. ;;requested (Idle loop)
  323. ;;
  324. ;         pushf
  325. ;         inc  [idle]
  326. ;         pushf
  327. ;         call [Int28]
  328. ;         call Activate
  329. ;         dec  [idle]
  330. ;         popf
  331. ;         iret
  332. ;Server28 endp
  333. ;
  334. ;;
  335. ;;Catch routines for dos interrupts
  336. ;;
  337. ;
  338. ;Catch2a  proc far
  339. ;;
  340. ;;Int 2ah Critical phase
  341. ;;
  342. ;         pushf
  343. ;         cmp  ah,80h                    ;start crit section ?
  344. ;         je   act                       ;yes
  345. ;         cmp  ah,81h                    ;end crit section
  346. ;         je   deact                     ;yes
  347. ;         cmp  ah,87h                    ;start/end crit section ?
  348. ;         jne  ok                        ;no
  349. ;         cmp  al,0                      ;start ?
  350. ;         je   act                       ;yes
  351. ;         cmp  al,1                      ;end ?
  352. ;         jne  ok                        ;no
  353. ;deact:                                  ;end crit section
  354. ;         inc  [doscrit]
  355. ;         jmp  ok
  356. ;act:                                    ;start crit section
  357. ;         dec  [doscrit]
  358. ;ok:
  359. ;         popf
  360. ;         jmp  [Int2a]
  361. ;Catch2a  endp
  362. ;
  363. ;Server2f proc far
  364. ;;
  365. ;;called by int2f to perform program id dependant functions
  366. ;;ah = id
  367. ;;al = 0  - return pointer to executable name
  368. ;;     1  - return vectors for de-installation
  369. ;;     2+ - user functions (via 'Server' procedure of TsrInstall)
  370. ;;
  371. ;         pushf
  372. ;         cmp  ah,id                     ;is this our id ?
  373. ;         je   send
  374. ;         popf
  375. ;         jmp  [Int2f]                   ;no, so continue elsewhere
  376. ;send:                                   ;check function
  377. ;         popf
  378. ;         push ds
  379. ;         push bx
  380. ;         mov  bx,data
  381. ;         mov  ds,bx
  382. ;         cmp  al,0                      ;already installed ?
  383. ;         jne  tst1
  384. ;         mov  es,bx
  385. ;         mov  di,offset [ExeName]
  386. ;         xchg al,ah
  387. ;         pop  bx
  388. ;         pop  ds
  389. ;         iret
  390. ;tst1:
  391. ;         pop  bx
  392. ;         cmp  al,1                      ;vectors for de-installation ?
  393. ;         jne  user2f
  394. ;         mov  ax,cs
  395. ;         mov  es,ax
  396. ;         mov  bx,offset Server
  397. ;         mov  di,offset Int08
  398. ;         mov  dx,PrefixSeg
  399. ;         pop  ds
  400. ;         iret
  401. ;user2f:
  402. ;         sub   ah,ah
  403. ;         call  User2FServer
  404. ;          pop   ds
  405. ;         iret
  406. ;Server2f endp
  407. ;
  408. ;SetUp    proc near                      ;SetUp(Key:Word)
  409. ;;
  410. ;;Setup takes care of accessing variables in the code
  411. ;;segment of this object module
  412. ;;
  413. ;         pop  bx                        ;return address
  414. ;         pop  ax                        ;parameter "key"
  415. ;         mov  HotKey,ax
  416. ;         mov  al,Int2fId
  417. ;         mov  id,al
  418. ;         push bx
  419. ;         push es
  420. ;         push ds
  421. ;         mov  ah,34h                    ;get InDos flag address
  422. ;         int  21h
  423. ;         pop  ds
  424. ;         mov  word ptr [InDosAdr],bx
  425. ;         mov  word ptr [InDosAdr+2],es
  426. ;         pop  es
  427. ;         pop  bx
  428. ;         ;now let OldInts^ and NewInts^ from the pascal part
  429. ;         ;point to the corresponding data in the code
  430. ;         ;segment of this object module
  431. ;         mov  word ptr [OldInts],offset Int08
  432. ;         mov  word ptr [OldInts+2],cs
  433. ;         mov  word ptr [NewInts],offset Server
  434. ;         mov  word ptr [NewInts+2],cs
  435. ;         jmp  bx
  436. ;SetUp    endp
  437. ;
  438. ;Dummy1b  proc far
  439. ;;
  440. ;;dummy ctrl-break handler
  441. ;;is active while tsr is active because a ctrl-break
  442. ;;would be fatal otherwise...
  443. ;;
  444. ;         iret
  445. ;Dummy1b  endp
  446. ;
  447. ;code     ends
  448. ;end
  449. ;;
  450. ;; end of tsr.asm
  451. ;;
  452. *)
  453.  
  454. (*
  455.  * here is where the actual pascal module starts
  456.  *)
  457. Unit tsr;
  458. {$S-,R-,A-,I-}
  459. (* no stack- and rangecheck,
  460.  * no word alignment,
  461.  * no io-check
  462.  *)
  463.  
  464. Interface
  465.  
  466. Uses
  467.   Dos;
  468.  
  469. {$ifdef debug}
  470. Uses
  471.   TpHex;
  472. {$endif}
  473.  
  474. Type
  475.   TsrProc = Procedure;
  476.  
  477. Procedure UserDummy;
  478.  
  479. Procedure TsrInstall( KeyName : String;    (* hotkey name *)
  480.                       KeyCode : Word;      (* hotkey scancode *)
  481.                       TsrId   : Byte;      (* unique id for int2f *)
  482.                       Proc    : TsrProc;   (* user hook *)
  483.                       Server  : TsrProc;   (* Int2f receiver *)
  484.                       Check   : TsrProc ); (* Int2f sender *)
  485.  
  486. Const
  487.   Error     : Integer = 0;
  488.  
  489. Var
  490.   HotKey    : Word;         (* keycode for activation *)
  491.   TsrLoaded : Boolean;
  492.  
  493. Implementation
  494.  
  495. Const
  496.   IntCnt       = 10;       (* replace 10 interrupts *)
  497.  
  498. Type
  499.   IntList      = Array[1..IntCnt] Of Pointer; (* original vectors *)
  500.   OfsList      = Array[1..IntCnt] Of Word;    (* offset of our vectors *)
  501.  
  502. Const
  503.   IntNum       : Array[1..IntCnt] Of Byte =   (* int # to be replaced *)
  504.     ($08, $09, $10, $13, $16, $25, $26, $28, $2a, $2f);
  505.  
  506. Var
  507.   UserProc     : TsrProc;   (* user hook *)
  508.   User2fServer : TsrProc;
  509.   (*
  510.    * OldInts and NewInts are filled by SetUp with adresses in CS
  511.    *)
  512.   OldInts      : ^IntList;  (* old vectors *)
  513.   NewInts      : ^OfsList;  (* new vectors *)
  514.   Int2fId      : Byte;      (* unique id for int2f *)
  515.   TurboSS      : Word;      (* turbo stack segment *)
  516.   TurboSP      : Word;      (* turbo stack pointer *)
  517.   ExeName      : String[8]; (* programname for identification and messages *)
  518.   DosBufSize   : Word;
  519.   DOSVars,                  (* Dos variables location *)
  520.   DOSBuffer    : Pointer;   (* Buffer to save the dos variables *)
  521.   TurboInt24   : Pointer;   (* Turbo critical error handler *)
  522.  
  523. {$L tsr.obj}
  524. Procedure SetUp( key : Word ); Near; External;
  525. Procedure Dummy1B; Far; External;
  526.  
  527. (*
  528.  * dos help functions
  529.  *)
  530.  
  531. Procedure SetPSP; Assembler;
  532. Asm
  533.   mov   ah,50h
  534.   mov   bx,PrefixSeg
  535.   int   21h
  536. End;
  537.  
  538. (*
  539.  * TurboFrame is called by int08h or int28h after the user pressed
  540.  * the hotkey
  541.  *)
  542.  
  543. Procedure TurboFrame; near;
  544. {$ifdef debug}
  545. Type
  546.   ar = array[1..100] of byte;
  547.   arptr = ^ar;
  548. {$endif}
  549. Var
  550.   i : byte;
  551.   ActInt09, ActInt16,
  552.   ActInt1b, ActInt24 : Pointer;
  553. Begin
  554.   (*
  555.    * swap active keyboard interrupts with our own
  556.    *)
  557.   GetIntVec( $09, ActInt09 );
  558.   GetIntVec( $16, ActInt16 );
  559.   SetIntVec( $09, OldInts^[2] );
  560.   SetIntVec( $16, OldInts^[5] );
  561.   (*
  562.    * disable ctrl-break
  563.    *)
  564.   GetIntVec( $1b, ActInt1b );
  565.   SetIntVec( $1b, @Dummy1B );
  566.   (*
  567.    * critical error
  568.    *)
  569.   GetIntVec( $24, ActInt24 );
  570.   SetIntVec( $24, TurboInt24 );
  571.   (*
  572.    * move dos variables
  573.    *)
  574.   Move( DOSVars^, DOSBuffer^, DosBufSize );
  575.  
  576. {$ifdef debug}
  577.   for i := 1 to dosbufsize do write(hexbyte(arptr(dosbuffer)^[i]));
  578.   writeln;
  579. {$endif}
  580.  
  581.   (*
  582.    * setup PSP of TSR
  583.    *)
  584.   SetPSP;
  585.  
  586.  (*
  587.   * This is why all this is done
  588.   *)
  589.   UserProc;
  590.  
  591.   (*
  592.    * restore old situation
  593.    *)
  594.   Move( DOSBuffer^, DOSVars^, DosBufSize );
  595.   SetIntVec( $09, ActInt09 );
  596.   SetIntVec( $16, ActInt16 );
  597.   SetIntVec( $1b, ActInt1b );
  598.   SetIntVec( $24, ActInt24 );
  599. End;
  600.  
  601. Procedure TsrInstall( KeyName : String;
  602.                       KeyCode : Word;
  603.                       TsrId   : Byte;
  604.                       Proc    : TsrProc;
  605.                       Server  : TsrProc;
  606.                       Check   : TsrProc );
  607. Var
  608.   i           : Byte;
  609.   ProgSegs    : Word;
  610.   CmdLn       : String;
  611.   p           : Pointer;
  612.  
  613.   Procedure FreeMemBlock( BlockSeg : Word ); assembler;
  614.   (*
  615.    * function 49h
  616.    *)
  617.   Label
  618.     fin;
  619.   Asm
  620.     mov   ah,49h        { free allocated memory }
  621.     mov   es,BlockSeg   { block segment }
  622.     int   21h           { dos interrupt }
  623.     jc    fin           { carry indicates error }
  624.     sub   ax,ax
  625.   fin:
  626.     mov   Error,ax
  627.   End;
  628.  
  629.   Function DosVersion : Word; Assembler;
  630.   Asm
  631.     mov   ax,3000h
  632.     int   21h
  633.   End;
  634.  
  635.   Function GetDosVars : Boolean; Assembler;
  636.   Label
  637.     ok,fin;
  638.   Asm
  639.     push  ds
  640.     mov   ax,5d06h              (* get dos swappable data area in ds:si *)
  641.     int   21h
  642.     jnc   ok
  643.     xor   ax,ax
  644.     pop   ds
  645.     jmp   fin
  646.   ok:
  647.     mov   ax,ds
  648.     pop   ds
  649.     mov   word ptr [DOSVars],si
  650.     mov   word ptr [DOSVars+2],ax
  651.     mov   DosBufSize,dx          (* cx = total, dx = head *)
  652.     mov   al,1
  653.   fin:
  654.   End;
  655.  
  656.   Procedure GetExeName;
  657.   Var
  658.     i : Byte;
  659.     s : String;
  660.   Begin
  661.     s := ParamStr(0);
  662.     i := Length(s);
  663.     While (s[i] <> '\') And (s[i] <> ':') And (i > 0) Do
  664.       Dec(i);
  665.     Exename := Copy(s,i+1,Length(s)-(i+4));
  666.   End;
  667.  
  668.   (*
  669.    * TsrInstalled checks via int2fh if program is installed
  670.    *)
  671.   Function TsrInstalled : Boolean;
  672.   Var
  673.     nseg, noff : Word;
  674.     id         : Byte;
  675.   Begin
  676.     Asm
  677.       mov  ah,Int2fId
  678.       sub  al,al
  679.       int  2fh
  680.       mov  nseg,es
  681.       mov  noff,di
  682.       mov  id,al
  683.     End;
  684.     TsrInstalled := (string(ptr(nseg,noff)^) = ExeName) And (id = Int2fId);
  685.   End;
  686.  
  687.   (*
  688.    * for TsrInstall messages
  689.    *)
  690.   Procedure MsgHalt( msg : String );
  691.   Begin
  692.     WriteLn(msg);
  693.     Halt;
  694.   End;
  695.  
  696. Begin
  697.   Int2fId := TsrId;
  698.   GetExeName;
  699.   TsrLoaded := TsrInstalled;
  700.   If Swap(DosVersion) < $030a Then
  701.     MsgHalt('Dos version 3.10 or higher required');
  702.   If ParamCount > 0 Then Begin
  703.     CmdLn := ParamStr(1);
  704.     For i := 1 To 2 Do
  705.       CmdLn[i] := UpCase(CmdLn[i]);
  706.     If TsrLoaded Then Begin
  707.       If (CmdLn = '/U') Then Begin
  708.         (* TSR removal, call int 2f to get the vectors and segment *)
  709.         Asm
  710.           mov   ah,Int2fId
  711.           mov   al,1
  712.           int   2fh
  713.           mov   word ptr [NewInts],bx
  714.           mov   word ptr [NewInts+2],es
  715.           mov   word ptr [OldInts],di
  716.           mov   word ptr [OldInts+2],es
  717.           mov   ProgSegs,dx
  718.         End;
  719.         (*
  720.          * Are these vectors still ours ?
  721.          *)
  722.         For i := 1 To IntCnt Do Begin
  723.           GetIntVec( IntNum[i], p );
  724.           If Ptr(Seg(NewInts^),NewInts^[i]) <> p Then
  725.             MsgHalt(ExeName+'not loaded last in interrupt chain - not removed!');
  726.         End;
  727.         (*
  728.          * restore old vectors
  729.          *)
  730.         For i := 1 To IntCnt Do
  731.           SetIntVec( IntNum[i], OldInts^[i] );
  732.         (*
  733.          * free up memory
  734.          *)
  735.         FreeMemBlock(ProgSegs);
  736.         If Error <> 0 Then
  737.           MsgHalt('Dos error: could not deallocate memory.')
  738.         Else
  739.           MsgHalt(ExeName+' removed from memory.');
  740.       End (* CmdLn = '/U' *) Else Begin (* CmdLn <> '/U' *)
  741.         (*
  742.          * At this point all commandline parameters <> '/U'
  743.          * can be handled for the loaded Tsr
  744.          *)
  745.         If Addr(Check) <> Nil Then
  746.           Check;
  747.       End (* CmdLn <> '/U' *);
  748.       Halt;
  749.     End (* Loaded *) Else Begin (* Not Loaded *)
  750.       If (CmdLn = '/U') Then
  751.         MsgHalt(ExeName+' is not resident.')
  752.       Else Begin (* CmdLn <> '/U' *)
  753.         (*
  754.          * At this point all commandline parameters <> '/U'
  755.          * can be handled for the Tsr to be installed.
  756.          *)
  757.         If Addr(Check) <> Nil Then
  758.           Check;
  759.       End (* CmdLn <> '/U' *);
  760.     End (* Not Loaded *);
  761.   End (* ParamCount > 0 *);
  762.  
  763.   If TsrLoaded Then
  764.     MsgHalt(ExeName+' is already resident'^m^j'Hotkey : '+KeyName);
  765.  
  766.   (*
  767.    * here is where the installation starts
  768.    *)
  769.   TurboSS      := SSeg;
  770.   TurboSP      := SPtr - $200;
  771.  
  772.   If Addr(Proc) <> Nil Then
  773.     UserProc := Proc
  774.   Else
  775.     UserProc := UserDummy;
  776.  
  777.   If Addr(Server) <> Nil Then
  778.     User2fServer := Server
  779.   Else
  780.     User2fServer := UserDummy;
  781.  
  782.   If Not GetDosVars Then
  783.     MsgHalt('Dos variables not located.');
  784.  
  785.   Setup( KeyCode );
  786.  
  787.   (*
  788.    * save original vectors and set new ones
  789.    *)
  790.   For i := 1 To IntCnt Do Begin
  791.     GetIntVec( Intnum[i], OldInts^[i] );
  792.     SetIntVec( IntNum[i], Ptr(CSeg,NewInts^[i]) );
  793.   End;
  794.  
  795.   (*
  796.    * get Turbo error handler
  797.    *)
  798.   GetIntVec( $24, TurboInt24 );
  799.  
  800.   WriteLn(ExeName+' is resident.'^m^j'Hotkey : '+KeyName);
  801.  
  802.   (*
  803.    * calculate programsize and set it
  804.    *)
  805.   ProgSegs := Seg(HeapPtr^)+1-PrefixSeg;
  806.  
  807.   (*
  808.    * Free up environment
  809.    *)
  810.   FreeMemBlock(MemW[PrefixSeg:$2c]);
  811.  
  812.   (*
  813.    * tsrinstall will no longer be used, so place DOSBuffer at
  814.    * position of this routine (saves space)
  815.    *)
  816.   DOSBuffer := @TsrInstall;
  817.  
  818.   SwapVectors;
  819.  
  820.   (*
  821.    * stay resident
  822.    *)
  823.   Asm
  824.     mov   ax,3100h              (* keep *)
  825.     mov   dx,[ProgSegs]
  826.     int   21h
  827.   End;
  828. End;
  829.  
  830. (*
  831.  * UserDummy can be used if no 'remote' control is required
  832.  *)
  833. Procedure UserDummy; Assembler;
  834. Asm
  835. End;
  836.  
  837. End.
  838.